#include <iostream>
#include <fstream>
#include <iomanip>

#include "main.h"
#include "ar8030_usb_tool.h"
#include "ar_usb.h"

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>
#else
#include <Windows.h>
#include <WinBase.h>
#endif


/******************************INDEX DEFINE*****************************/
#define     INDEX_SYS_UPGRADE       0
#define     INDEX_SYS_FILETRAN      1
#define     INDEX_SYS_FILEGET       2
#define     INDEX_SYS_USBCMD        3
#define     INDEX_UBOOT_FILETRAN    4
#define     INDEX_UBOOT_FILEGET     5
#define     INDEX_UBOOT_USBCMD      6

#define     MAX_CMD_LEN             256
#define     MAX_FILE_LEN            256


#define     upgrade_start_mark      "upgd"
#define     filetran_start_mark     "file"
#define     fileget_start_mark      "fget"
#define     usbcmd_start_mark       "ucmd"
#define     ufiletran_start_mark    "uftr"
#define     ufileget_start_mark     "ufgt"
#define     uusbcmd_start_mark      "uucd"

#define 	OTA_IMG_MAGIC 			(0x4152544f)

#define     GPT_FLASH_OFFSET        (0x8000)
#define     GPT_FLASH_SIZE          (0x1000)

#pragma pack(push)
#pragma pack(1)


typedef struct
{
    unsigned int    magic;
    unsigned short  img_type;
    unsigned short  header_len;
    unsigned int    header_checksum;
    unsigned int    img_version;
    unsigned int    flag;
    unsigned int    boot_info;
    unsigned int    spl_load_addr;
    unsigned int    spl_len;
    unsigned int    troot_load_addr;
    unsigned int    troot_len;
    unsigned int    signature_load_addr;
    unsigned int    signature_len;
    unsigned int    spl_dtb_offset;
    unsigned long   checksum;
    unsigned int    id_masks;
    unsigned char   patch_len[8];
    //unsigned char   patch[0];
}STRU_SPL_HEADER;

#pragma pack(pop)

using namespace std;
#define TEST_BUFFER_LEN             (1024 * 4)//(4 * 1024 * 1024)
#define BUFF_UNIT               (4096)
static unsigned char g_test_buffer[TEST_BUFFER_LEN];

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
unsigned long get_time_diff(struct timeval _old, struct timeval _new)
{
    unsigned long old_usec = _old.tv_sec * 1000000 + _old.tv_usec;
    unsigned long new_usec = _new.tv_sec * 1000000 + _new.tv_usec;
    unsigned long ret = 0;

    ret = new_usec - old_usec;

    if (0 == ret)
        ret = 1;
    return ret;
}
#endif

ar8030_usb_tool::ar8030_usb_tool()
{
    usb = new ar_usb();
}

ar8030_usb_tool::~ar8030_usb_tool()
{
    if (usb)
    {
        delete usb;
    }
}

unsigned char usb_cal_checksum(unsigned char* data, unsigned int len)
{
    int i = 0;
    unsigned int tmp_checksum = 0;
    for (i = 0; i < len; ++i)
    {
        tmp_checksum += data[i];
    }

    return tmp_checksum & 0xff;
}

int ar8030_usb_tool::send_speed_test()
{
    unsigned long long total_data = 0;
    STRU_ARTO_HID_HEADER* p_tx = (STRU_ARTO_HID_HEADER*)g_test_buffer;
    unsigned char* p_tx_data = g_test_buffer + sizeof(STRU_ARTO_HID_HEADER);
    unsigned int i = 0;
    unsigned long long* p_index = (unsigned long long*)p_tx_data;

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    struct timeval  timestamp_0, timestamp_1;
#else
    DWORD           timestamp_0, timestamp_1;

    LARGE_INTEGER  nFreq, t1, t2;

    double dt;

    QueryPerformanceFrequency(&nFreq);
   
#endif

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    gettimeofday(&timestamp_0, NULL);
#else
    timestamp_0 = GetTickCount();

    QueryPerformanceCounter(&t1);
#endif

    p_tx->magic[0] = 'A';
    p_tx->magic[1] = 'U';
    p_tx->port_index = 0x02;
    p_tx->header_len = sizeof(STRU_ARTO_HID_HEADER);
    p_tx->data_len = TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER) - 1;
    p_tx->status = 0;

    for (int i = 0; i < p_tx->data_len; ++i)
    {
        p_tx_data[i] = (rand() & 0xff);
    }
    *p_index = 0;

    while (1)
    {
        //p_tx->data_len = rand() % (512 - sizeof(STRU_ARTO_HID_HEADER) - 8) + 8;
        p_tx->data_len = rand() % (TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER) - 8) + 8;
        //p_tx->data_len = rand() % (TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER));
        //p_tx->data_len = TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER) - 1;
        //++i;
        p_tx->checksum = usb_cal_checksum(p_tx_data, p_tx->data_len);
        if (LIBUSB_SUCCESS == usb->usb_hid_write(handle, g_test_buffer, p_tx->data_len + sizeof(STRU_ARTO_HID_HEADER), 60000))
        {
            total_data += (p_tx->data_len + sizeof(STRU_ARTO_HID_HEADER));
            //printf("send success %llu\n", total_data);
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
            gettimeofday(&timestamp_1, NULL);//timestamp_1 = GetTickCount();
            if (get_time_diff(timestamp_0, timestamp_1) > 1000000)
            {
                cout << "image send speed:" << total_data * 1000 / get_time_diff(timestamp_0, timestamp_1) << "KB/s" << endl;
                total_data = 0;
                gettimeofday(&timestamp_0, NULL);
            }
#else
            QueryPerformanceCounter(&t2);
            dt = (t2.QuadPart - t1.QuadPart) / (double)nFreq.QuadPart;
            if (dt > 1.0)
            {
                printf("send success %llu\n", total_data);
                cout << "image send speed:" << total_data / (dt * 1000) << "KB/s" << endl;
                total_data = 0;
                QueryPerformanceCounter(&t1);
            }
#endif
        }
        (*p_index)++;
    }
    return 0;
}

int ar8030_usb_tool::recv_speed_test()
{
    unsigned long long total_data = 0;
    int ret = 0;
    STRU_ARTO_HID_HEADER* p_tx = (STRU_ARTO_HID_HEADER*)g_test_buffer;

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    struct timeval  timestamp_0, timestamp_1;
#else
    DWORD           timestamp_0, timestamp_1;
#endif
    printf("%s start!\n", __func__);
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    gettimeofday(&timestamp_0, NULL);
#else
    timestamp_0 = GetTickCount();
#endif

    p_tx->magic[0] = 'A';
    p_tx->magic[1] = 'U';
    p_tx->port_index = 0x03;
    p_tx->header_len = sizeof(STRU_ARTO_HID_HEADER);
    p_tx->data_len = TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER) - 1;
    p_tx->status = 0;

    if (LIBUSB_SUCCESS != usb->usb_hid_write(handle, g_test_buffer, p_tx->data_len + sizeof(STRU_ARTO_HID_HEADER), 60000))
    {
        return -1;
    }

    while (1)
    {
        if ((ret = usb->usb_hid_read(handle, g_test_buffer, TEST_BUFFER_LEN, 60000)) > 0)
        {
            total_data += ret;
            //printf("recv success %d\n", TEST_BUFFER_LEN);
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
            gettimeofday(&timestamp_1, NULL);//timestamp_1 = GetTickCount();
            cout << "image send speed:" << total_data * 1000 / get_time_diff(timestamp_0, timestamp_1) << "KB/s" << endl;
#else
            timestamp_1 = GetTickCount();
            if (timestamp_1 - timestamp_0 > 1000)
            {
                cout << "image recv speed:" << total_data / (timestamp_1 - timestamp_0) << "KB/s" << endl;
                total_data = 0;
                timestamp_0 = GetTickCount();
            }
#endif
        }
    }
    return 0;
}

int ar8030_usb_tool::echo_speed_test()
{
    unsigned char tx_buffer[BUFF_UNIT];
    unsigned char rx_buffer[BUFF_UNIT];

    STRU_ARTO_HID_HEADER* p_tx = (STRU_ARTO_HID_HEADER*)tx_buffer;
    STRU_ARTO_HID_HEADER* p_rx = (STRU_ARTO_HID_HEADER*)rx_buffer;
    unsigned char* p_tx_data = tx_buffer + sizeof(STRU_ARTO_HID_HEADER);
    unsigned char* p_rx_data = rx_buffer + sizeof(STRU_ARTO_HID_HEADER);
    //unsigned long* p_tx_timestamp = (unsigned long*)p_tx_data;
    //unsigned long* p_rx_timestamp = (unsigned long*)p_rx_data;

    unsigned int i = 0;

    unsigned long long total_data = 0;

    p_tx->magic[0] = 'A';
    p_tx->magic[1] = 'U';
    p_tx->port_index = 0x01;
    p_tx->header_len = sizeof(STRU_ARTO_HID_HEADER);
    p_tx->data_len = BUFF_UNIT - sizeof(STRU_ARTO_HID_HEADER);
    p_tx->status = 0;

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    struct timeval  timestamp_0, timestamp_1;
#else
    DWORD           timestamp_0, timestamp_1;
    LARGE_INTEGER  nFreq, t1, t2;

    double dt;

    QueryPerformanceFrequency(&nFreq);
#endif

#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    gettimeofday(&timestamp_0, NULL);

    unsigned long long * p_tx_timestamp = (unsigned long long*)p_tx_data;
    unsigned long long* p_rx_timestamp = (unsigned long long*)p_rx_data;
#else
    timestamp_0 = GetTickCount();
    QueryPerformanceCounter(&t1);

    LARGE_INTEGER* p_tx_timestamp = (LARGE_INTEGER*)p_tx_data;
    LARGE_INTEGER* p_rx_timestamp = (LARGE_INTEGER*)p_rx_data;
#endif

    while (1)
    {
        p_tx->data_len = TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER);//(rand() % (TEST_BUFFER_LEN - sizeof(STRU_ARTO_HID_HEADER) - 4)) + 4;
        unsigned int send_len = p_tx->data_len + p_tx->header_len;

        p_tx->checksum = 0;
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
        gettimeofday(&timestamp_0, NULL);
        *p_tx_timestamp = timestamp_0.tv_sec * 1000000 + timestamp_0.tv_usec;
#else
        QueryPerformanceCounter(&t2);
        *p_tx_timestamp = t2;
#endif
        
        if (LIBUSB_SUCCESS == usb->usb_hid_write(handle, (unsigned char *)tx_buffer, send_len, 1000))
        {
            //usb->usb_hid_write(handle, (unsigned char*)tx_buffer, send_len, 1000);
            //p_tx->data_len = 112;
            //send_len = p_tx->data_len + p_tx->header_len;
            //usb->usb_hid_write(handle, (unsigned char*)tx_buffer, send_len, 1000);
            if (0 <= usb->usb_hid_read(handle, (unsigned char*)rx_buffer, send_len, 10000))
            {
                total_data += send_len;
                printf("%d: echo success %llu\n", i, total_data);
                
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
                gettimeofday(&timestamp_1, NULL);//timestamp_1 = GetTickCount();
                cout << "image send speed:" << total_data / (get_time_diff(timestamp_0, timestamp_1) / 1000) << "KB/s" << endl;
#else
                timestamp_1 = GetTickCount();
                QueryPerformanceCounter(&t2);

                dt = (t2.QuadPart - (*p_rx_timestamp).QuadPart) / (double)nFreq.QuadPart;
                //if (t2 - *p_tx_timestamp)
                {
                    cout << "time cost:" << dt * 1000000 << "us" << endl;
                    cout << "image send speed:" << BUFF_UNIT * 2 * sizeof(char) / (dt * 1000) << "KB/s" << endl;
                }
#endif
                //printf("%x %d %08x != %08x\n", i, 3, tx_buffer[0], rx_buffer[3]);

                //if(i > 2) return 0;
                /*if (0 == memcmp(tx_buffer, rx_buffer, BUFF_UNIT * sizeof(int)))
                    cout << "image check scuess!" << endl;
                else
                {
                    cout << "image check failed!" << endl;
                    for (int j = 0; j < BUFF_UNIT; ++j)
                    {
                        if(tx_buffer[j] != rx_buffer[j])
                            printf("%d %d %x != %x\n", i, j, tx_buffer[j], rx_buffer[j]);
                    }
                }*/
            }
            else
            {
                printf("%d: echo read failed %llu\n", i, total_data);
            }
        }
        else
        {
            printf("%d: echo write failed %llu\n", i, total_data);
        }
        ++i;
    }
    return 0;
}
#define tole(x) (x)

const uint32_t crc_table[256] = {
tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
};

#define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
typedef unsigned char Bytef;
typedef unsigned int  uInt;
/* ========================================================================= */

/* No ones complement version. JFFS2 (and other things ?)
 * don't use ones compliment in their CRC calculations.
 */
uint32_t crc32_no_comp(uint32_t crc, const Bytef* buf, uInt len)
{
    const uint32_t* tab = crc_table;
    const uint32_t* b = (const uint32_t*)buf;
    size_t rem_len;

    crc = (crc);
    /* Align it */
    if (((long)b) & 3 && len) {
        uint8_t* p = (uint8_t*)b;
        do {
            DO_CRC(*p++);
        } while ((--len) && ((long)p) & 3);
        b = (uint32_t*)p;
    }

    rem_len = len & 3;
    len = len >> 2;
    for (--b; len; --len) {
        /* load data 32 bits wide, xor data 32 bits wide. */
        crc ^= *++b; /* use pre increment for speed */
        DO_CRC(0);
        DO_CRC(0);
        DO_CRC(0);
        DO_CRC(0);
    }
    len = rem_len;
    /* And the last few bytes */
    if (len) {
        uint8_t* p = (uint8_t*)(b + 1) - 1;
        do {
            DO_CRC(*++p); /* use pre increment for speed */
        } while (--len);
    }

    return (crc);
}
#undef DO_CRC

uint32_t crc32(uint32_t crc, const Bytef* p, uInt len)
{
    return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL;
}


//usb protocol
int ar8030_usb_tool::ar8030_hid_read(unsigned char* data, unsigned short len, unsigned int port)
{
    unsigned char* rx_buffer = NULL;
    STRU_ARTO_HID_HEADER* p_usb_header = NULL;
    int ret = -1;

    if (NULL == data || len > ARTO_HID_MAX_SIZE)
    {
        return -1;
    }

    rx_buffer = (unsigned char*)malloc(len + sizeof(STRU_ARTO_HID_HEADER));
    if (NULL == rx_buffer)
    {
        return -1;
    }

    if (0 <= usb->usb_hid_read(handle, (unsigned char*)rx_buffer, len + sizeof(STRU_ARTO_HID_HEADER), 10000))
    {
        p_usb_header = (STRU_ARTO_HID_HEADER*)rx_buffer;
        if (port == p_usb_header->port_index)
        {
            ret = 0;
            memcpy(data, rx_buffer + sizeof(STRU_ARTO_HID_HEADER), len);
        }
    }

    free(rx_buffer);
    return ret;
}

int ar8030_usb_tool::ar8030_hid_write(void * header, unsigned int head_size, unsigned char* data, unsigned short len, unsigned int port)
{
    unsigned char* tx_buffer = NULL;
    STRU_ARTO_HID_HEADER * p_usb_header = NULL;
    int ret = 0;

    if (NULL == header || (head_size + len) > ARTO_HID_MAX_SIZE)
    {
        return -1;
    }

    tx_buffer = (unsigned char*)malloc((head_size + len) + sizeof(STRU_ARTO_HID_HEADER));
    if (NULL == tx_buffer)
    {
        return -1;
    }
    memset(tx_buffer, 0, (head_size + len) + sizeof(STRU_ARTO_HID_HEADER));

    p_usb_header = (STRU_ARTO_HID_HEADER*)tx_buffer;
    p_usb_header->magic[0] = 'A';
    p_usb_header->magic[1] = 'U';
    p_usb_header->port_index = port;
    p_usb_header->header_len = sizeof(STRU_ARTO_HID_HEADER);
    p_usb_header->data_len = (head_size + len);
    p_usb_header->checksum = 0;

    memcpy(tx_buffer + sizeof(STRU_ARTO_HID_HEADER), header, head_size);
    if(data && len)
        memcpy(tx_buffer + sizeof(STRU_ARTO_HID_HEADER) + head_size, data, len);

    if (LIBUSB_SUCCESS == usb->usb_hid_write(handle, (unsigned char*)tx_buffer, (head_size + len) + sizeof(STRU_ARTO_HID_HEADER), 1000))
    {
        ret = 0;
    }
    else
    {
        ret = -1;
    }

    free(tx_buffer);
    return ret;
}

//upgrade protocal
int ar8030_usb_tool::ar8030_upgrade_read(unsigned long long addr, unsigned short len, unsigned char* data)
{
    STRU_ARTO_UPGRADE_HEADER up_header = { 0 };
    STRU_ARTO_UPGRADE_HEADER* p_up_header = NULL;
    unsigned char* rx_buffer = NULL;
    int ret = -1;

    rx_buffer = (unsigned char*)malloc(sizeof(STRU_ARTO_UPGRADE_HEADER));
    if (NULL == rx_buffer)
        return -1;

    up_header.magic = ARTO_UPGRADE_MAGIC;
    up_header.addr_h = (unsigned int)(addr >> 32);
    up_header.addr_l = (unsigned int)(addr & 0xffffffffULL);
    up_header.length = len;
    up_header.cmd = AR_UPGRADE_READ;

    ret = ar8030_hid_write(&up_header, sizeof(up_header), NULL, 0, ARTO_HID_PORT_UPGD);
    if (ret < 0)
    {
        printf("ar8030_upgrade_read cmd send failed!\n");
        return -1;
    }

    ret = ar8030_hid_read(rx_buffer, sizeof(STRU_ARTO_UPGRADE_HEADER) + len, ARTO_HID_PORT_UPGD);
    if (ret < 0)
        return -1;

    p_up_header = (STRU_ARTO_UPGRADE_HEADER*)rx_buffer;
    if (AR_UPGRADE_ACK == p_up_header->cmd &&
        AR_UPGRADE_RESPONSE_OK == p_up_header->response &&
        len == p_up_header->length)
    {
        ret = 0;
        memcpy(data, rx_buffer + sizeof(STRU_ARTO_UPGRADE_HEADER), len);
    }

    free(rx_buffer);
    return ret;
}

int ar8030_usb_tool::ar8030_upgrade_write(unsigned long long addr, unsigned short len, unsigned char * data)
{
    STRU_ARTO_UPGRADE_HEADER up_header = { 0 };
    if (len > ARTO_UPGRADE_MAX_SIZE || NULL == data)
        return -1;

    up_header.magic = ARTO_UPGRADE_MAGIC;
    up_header.addr_h = (unsigned int)(addr >> 32);
    up_header.addr_l = (unsigned int)(addr & 0xffffffffULL);
    up_header.length = len;
    up_header.cmd = AR_UPGRADE_WRITE;
    
    return ar8030_hid_write(&up_header, sizeof(up_header), data, len, ARTO_HID_PORT_UPGD);
}

int ar8030_usb_tool::ar8030_upgrade_wait_ack()
{
    STRU_ARTO_UPGRADE_HEADER * p_up_header = NULL;
    unsigned char* rx_buffer = NULL;
    int ret = -1;

    rx_buffer = (unsigned char*)malloc(sizeof(STRU_ARTO_UPGRADE_HEADER));
    if (NULL == rx_buffer) {
        printf("malloc failed\n");
        return -1;
    }

    ret = ar8030_hid_read(rx_buffer, sizeof(STRU_ARTO_UPGRADE_HEADER), ARTO_HID_PORT_UPGD);
    if (ret < 0) {
        printf("ack failed timeout\n");
        return -1;
    }

    p_up_header = (STRU_ARTO_UPGRADE_HEADER*)rx_buffer;
    if (AR_UPGRADE_ACK == p_up_header->cmd && AR_UPGRADE_RESPONSE_OK == p_up_header->response)
        ret = 0;
    else {
        printf("ack failed %x %x\n", p_up_header->cmd, p_up_header->response);
        ret = -1;
    }

    free(rx_buffer);
    return ret;
}

int ar8030_usb_tool::ar8030_upgrade_chk_crc(unsigned long long addr, unsigned int len, unsigned int target_crc)
{
    STRU_ARTO_UPGRADE_HEADER up_header = { 0 };
    STRU_ARTO_UPGRADE_CRC_HEADER crc;

    up_header.magic = ARTO_UPGRADE_MAGIC;
    up_header.addr_h = (unsigned int)(addr >> 32);
    up_header.addr_l = (unsigned int)(addr & 0xffffffffULL);
    up_header.length = sizeof(crc);
    up_header.cmd = AR_UPGRADE_CRC32;

    crc.length = len;
    crc.target_crc = target_crc;

    //printf("addr 0x%llx len %d crc 0x%x\n", addr, len, target_crc);

    return ar8030_hid_write(&up_header, sizeof(up_header), (unsigned char *)&crc, sizeof(crc), ARTO_HID_PORT_UPGD);
}

//upgrade control
int ar8030_usb_tool::ar8030_upgrade_partition(unsigned long long addr, unsigned int len, unsigned char* data)
{
    unsigned int o_crc = 0;
    unsigned int i = 0;
    unsigned int offset = 0;
    int ret = 0;

    printf("%s %d addr 0x%llx len %d\n", __func__, __LINE__, addr, len);

    //cal crc
    o_crc = crc32(0, data, len);

    //split
    for (i = 0; i < (len / ARTO_UPGRADE_MAX_SIZE); ++i)
    {
        //write 4KB
        offset = i * ARTO_UPGRADE_MAX_SIZE;
        ret = ar8030_upgrade_write(addr + offset, ARTO_UPGRADE_MAX_SIZE, data + offset);
        if (ret < 0)
        {
            printf("ar8030_upgrade_write failed!\n");
            return -1;
        }

        //wait ack
        ret = ar8030_upgrade_wait_ack();
        if (ret < 0)
        {
            printf("%s %d failed!\n", __func__, __LINE__);
            return -1;
        }
    }
    
    if (len % ARTO_UPGRADE_MAX_SIZE)
    {
        offset = i * ARTO_UPGRADE_MAX_SIZE;
        ret = ar8030_upgrade_write(addr + offset, len % ARTO_UPGRADE_MAX_SIZE, data + offset);
        if (ret < 0)
        {
            printf("ar8030_upgrade_write failed!\n");
            return -1;
        }

        //wait ack
        ret = ar8030_upgrade_wait_ack();
        if (ret < 0)
        {
            printf("%s %d failed!\n", __func__, __LINE__);
            return -1;
        }
    }
#if 1
    //get crc
    ret = ar8030_upgrade_chk_crc(addr, len, o_crc);
    if (ret < 0)
    {
        printf("ar8030_upgrade_chk_crc failed!\n");
        return -1;
    }

    //wait ack
    ret = ar8030_upgrade_wait_ack();
    if (ret < 0)
    {
        printf("%s %d ar8030_upgrade_wait_ack failed!\n", __func__, __LINE__);
        return -1;
    }
#endif
    return 0;
}

int get_part_info_offset(struct part_info* part_info, int nrparts, struct segment_info* segment)
{
    int i;

    /* avoid segments spreading over two partitions */
    for (i = 0; i < nrparts; i++) {
        if ((segment->flash_offset) >= (part_info[i].flash_offset)
            && (segment->flash_offset) + (segment->size_decompress)
            <= (part_info[i].flash_offset) + (part_info[i].length)) {
            return i;
        }
    }

    return -1;
}

int get_part_info_byname(struct part_info* part_info, int nrparts, const char * partname)
{
    int i;

    for (i = 0; i < nrparts; i++) {
        if (0 == strcmp((char *)part_info[i].name, partname)) {
            return i;
        }
    }

    return -1;
}

void print_buf(unsigned char* buf, int len)
{
    int i = 0;

    for (i = 0; i < len; ++i)
    {
        printf("%02x ", buf[i]);
        if (0 == ((i + 1) % 16) || (i == len - 1))
            printf("\n");
    }
}

int ar8030_usb_tool::do_verify_image(unsigned char* img)
{
    unsigned char* hash, * data, * sig;

    int ret = 0;
    struct upgrade_hdr* hdr;
    unsigned char* hdr_ext;
    unsigned char* romcode;
    unsigned char* bootloader;
    unsigned char* gpt;
    struct part_info* partitions;
    struct segment_info* segments;
    int i, m, n;
    int index_tmp, index;
    unsigned long long img_size;

    printf("Verify upgrade image...\n");

    /* Verify header */
    hdr = (struct upgrade_hdr*)img;

    if ((hdr->magic) != OTA_IMG_MAGIC ||
        (hdr->hash_size) != 32 ||
        (hdr->sig_size) != 256) {
        printf("error %d\n", __LINE__);
        return -1;
    }

    hash = img + sizeof(*hdr);
    sig = hash + 32;
    data = sig + 256;

    hdr = (struct upgrade_hdr*)img;
    hdr_ext = (unsigned char*)img + sizeof(*hdr);
    romcode = hdr_ext + 32 + 256 + (hdr->header_ext_size);
    bootloader = romcode + (hdr->rom_size);
    gpt = bootloader + (hdr->loader_size);
    partitions = (struct part_info*)(bootloader + GPT_FLASH_SIZE);
    segments = (struct segment_info*)(partitions + hdr->partitions);

    if ((hdr->rom_size) && (hdr->rom_size) > 0x8000) {
        printf("error %d\n", __LINE__);
        return -1;
    }

    if ((hdr->loader_size) && (hdr->loader_size) > 0x100000) {
        printf("error %d\n", __LINE__);
        return -1;
    }

    m = (hdr->partitions);
    n = (hdr->segments);

    index = -1;
    index_tmp = -1;
    img_size = 0;
    for (i = 0; i < n; i++) {
        index_tmp = get_part_info_offset(partitions, m, &segments[i]);
        if (index_tmp < 0) {
            printf("get part info based on segment flash offset failed\n");
            return -1;
        }

        /* the first partition */
        if (index == -1) {
            index = index_tmp;
        }

        /* the next partition */
        if (index != index_tmp) {
            if (img_size > (partitions[index].length)) {
                printf("image is too big, partition name: %s\n", partitions[index].name);
                return -1;
            }
            index = index_tmp;
            img_size = 0;
        }

        img_size += (segments[i].size_decompress);
    }

    /* the last partition */
    if (img_size > (partitions[index].length)) {
        printf("image is too big, partition name: %s\n", partitions[index].name);
        return -1;
    }

    printf("Verify upgrade image success\n");

    return 0;
}

int ar8030_usb_tool::dump_upgrade_file(unsigned char* buf)
{
    int i;
    struct upgrade_hdr* hdr = (struct upgrade_hdr*)buf;
    struct part_info* parts;
    struct segment_info* segments;

    printf("\n====================upgrade bin infomation====================\n\n");
    printf("magic:            0x%x\n", (hdr->magic));
    printf("hdr_version:      0x%x\n", hdr->hdr_version);
    printf("compressed:       0x%x\n", hdr->compressed);
    printf("flashtype:        0x%x\n", hdr->flashtype);
    printf("header_ext size:  0x%x\n", (hdr->header_ext_size));
    printf("hash size:        0x%x\n", (hdr->hash_size));
    printf("sig size:         0x%x\n", (hdr->sig_size));
    printf("sig_realsize:     0x%x\n", (hdr->sig_realsize));
    printf("img size:         0x%x\n", (int)(hdr->img_size));
    printf("rom_size:         0x%x\n", (hdr->rom_size));
    printf("loader_size:      0x%x\n", (hdr->loader_size));
    printf("partitions:       0x%x\n", (hdr->partitions));
    printf("segments:         0x%x\n", (hdr->segments));
    printf("obj_version:      0x%x\n", (hdr->object_version));
    printf("dep_version:      0x%x\n", (hdr->depend_version));
    if (hdr->part_status == PART_STATUS_NOCHANGE)
        printf("part_status:      no change\n");
    else if (hdr->part_status == PART_STATUS_CHANGE)
        printf("part_status:      changed\n");
    else
        printf("part_status:      unknown\n");
    printf("\n");

    buf += sizeof(*hdr);
    buf += (hdr->header_ext_size); /* now is 0 */
    printf("Hash:\n");
    print_buf(buf, 32);
    printf("\n");

    buf += 32;
    printf("RSA Signature:\n");
    print_buf(buf, 256);
    printf("\n");

    buf += 256;
    buf += (hdr->rom_size) + (hdr->loader_size) + GPT_FLASH_SIZE;

    parts = (struct part_info*)buf;

    /* init here, not when declarations, because uboot command upgrade many times */
    //partitions_size = 0;
    printf("Upgrade image partition table:\n");
    for (i = 0; i < (hdr->partitions); i++) {
        printf("part %d, name %8s, length 0x%08x, upgrade %d\n", i, parts->name, (int)parts->length, parts->is_upgrade);
        //partitions_size += (parts->length);
        parts++;
    }

    printf("\n");

    buf += sizeof(struct part_info) * (hdr->partitions);
    segments = (struct segment_info*)buf;

    printf("Upgrade image segments:\n");
    for (i = 0; i < (hdr->segments); i++) {
        printf("segment %03d, img offset=0x%08x, flash offset=0x%08x, compress size=0x%08x, decompress size=0x%08x\n",
               i,
               (int)segments->img_offset,
               (int)segments->flash_offset,
               (int)segments->size_compress,
               (int)segments->size_decompress);
        segments++;
    }

    printf("\n====================upgrade bin infomation done====================\n\n\n");

    return 0;
}

int ar8030_usb_tool::ar8030_upgrade_partition_byname(struct upgrade_hdr* hdr, struct part_info* partitions, 
    struct segment_info* segments, unsigned char * data, const char* partname)
{
    int i, ret = 0;
    int segment_idx = -1;
    unsigned long long partition_addr = 0;
    unsigned long long partition_len = 0;

    for (i = 0; i < hdr->partitions; i++) 
    {
        if (partitions[i].is_upgrade)
        {
            //printf("part %d, name %8s, length 0x%08llx, upgrade %d seg %d\n", i, 
            //    partitions[i].name, partitions[i].length, partitions[i].is_upgrade, segment_idx);
            ++segment_idx;
        }

        if (0 == strcmp((char*)partitions[i].name, partname)) 
        {
            break;
        }
    }

    //no not upgrade but return 0
    if (!partitions[i].is_upgrade)
        return 0;

    if (-1 == segment_idx || partitions[i].flash_offset != segments[segment_idx].flash_offset)
    {
        printf("partition %s info is not match! 0x%x 0x%x %d\n",
               partitions[i].name,
               (int)partitions[i].flash_offset,
               (int)segments[segment_idx].flash_offset,
               (int)segment_idx);
        return -1;
    }

    partition_addr = segments[segment_idx].flash_offset + GPT_FLASH_OFFSET;
    partition_len = segments[segment_idx].size_decompress;
    data += segments[segment_idx].img_offset;
    ret = ar8030_upgrade_partition(partition_addr, partition_len, data);
    if (ret < 0)
    {
        printf("upgrade partition %s failed!\n", partname);
    }
    return ret;
}

int ar8030_usb_tool::ar8030_upgrade(unsigned int index, std::string file_path)
{
    fstream         file_data;
    unsigned int    file_len, recv_len = 0;
    char* data = NULL;
    char* gpt_data = NULL;
    unsigned char* sendbuf = NULL, * recvbuf = NULL;
    unsigned int* p_len = NULL;

    struct upgrade_hdr* hdr;
    unsigned char* hdr_ext;
    unsigned char* romcode;
    unsigned char* bootloader;
    unsigned char* gpt;
    struct part_info* partitions;
    struct segment_info* segments;
    unsigned char* img;

    unsigned long long partition_addr = 0;
    unsigned long long partition_len = 0;
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    struct timeval  timestamp_0, timestamp_1;
#else
    DWORD           timestamp_0, timestamp_1;
#endif
    int             ret = -1;

    if (NULL == handle)
    {
        cout << "open usb device failed!" << endl;
        return -1;
    }

    //read upgrade data
    file_data.open(file_path, ios::in | ios::binary);
    if (!file_data.is_open())
    {
        cout << "file :" << file_path << " open failed!" << endl;
        return -1;
    }

    file_data.seekg(0, ios::end);
    file_len = file_data.tellg();
    file_data.seekg(0, ios::beg);

    try
    {
        data = new char[file_len];
        if (NULL == data)
        {
            cout << "new data failed!" << endl;
            return -1;
        }
    }
    catch (const bad_alloc& e)
    {
        cerr << "bad_alloc caught: " << e.what() << '\n';
        return -1;
    }

    file_data.read(data, file_len);
    file_data.close();

    if (0 == file_len)
    {
        cout << "image_size length is zero" << endl;
        return -1;
    }

    //verify image
    ret = do_verify_image((unsigned char*)data);
    if (ret < 0)
        return -1;

    //parse header(256 + 32 + 256)
    hdr = (struct upgrade_hdr*)data;
    hdr_ext = (unsigned char*)data + sizeof(*hdr);
    romcode = hdr_ext + 32 + 256 + (hdr->header_ext_size);
    bootloader = romcode + (hdr->rom_size);
    gpt = bootloader + (hdr->loader_size);
    partitions = (struct part_info*)(gpt + (GPT_FLASH_SIZE));
    segments = (struct segment_info*)(partitions + hdr->partitions);
    img = (unsigned char*)(segments + hdr->segments);

    dump_upgrade_file((unsigned char *)hdr);

    //return 0;//just for test

    //check gpt(to do)

    //write romcode
    if (hdr->rom_size)
    {
        ret = ar8030_upgrade_partition(0x0, hdr->rom_size, romcode);
        if (ret < 0)
            return -1;
    }

    //write gpt table 1
    partition_addr = 0x0 + hdr->rom_size + GPT_FLASH_SIZE;
    ret = ar8030_upgrade_partition(partition_addr, GPT_FLASH_SIZE, gpt);
    if (ret < 0)
        return -1;

    //write partitions app1
    ret = ar8030_upgrade_partition_byname(hdr, partitions, segments, (unsigned char*)data, "app1");
    if (ret < 0)
        return -1;

    //write gpt table 0
    partition_addr = 0x0 + hdr->rom_size;
    ret = ar8030_upgrade_partition(partition_addr, GPT_FLASH_SIZE, gpt);
    if (ret < 0)
        return -1;

    //write partitions app0
    ret = ar8030_upgrade_partition_byname(hdr, partitions, segments, (unsigned char *)data, "app0");
    if (ret < 0)
        return -1;

    //write other partitions
    //todo

    printf("upgrade done!\n");

    return 0;
}

void ar8030_usb_tool::usb_delay_ms(unsigned int ms)
{
#if (__CURRENT_PLATFORM__ == __LINUX_PLATFORM__)
    usleep(ms * 1000);
#else
    Sleep(ms);
#endif    
}

int ar8030_usb_tool::usb_tool_command_help()
{
    cout << "************************help************************" << __TIME__ << endl;
    cout << "-l                      list arto usb device" << endl;
    cout << "                        ==============>Device :N, Mode :ROMCODE MODE" << endl;
    cout << "                        Dev (bus 3, device 20): Artosyn - USB download gadget" << endl;
    cout << "                        ==============>Device :N + 1, Mode :NORMAL MODE" << endl;
    cout << "                        Dev (bus 3, device 20): Artosyn - USB download gadget" << endl;
    cout << "                        ==============>Device :N + 2, Mode :UPGRADE MODE" << endl;
    cout << "                        Dev (bus 3, device 20): Artosyn - USB download gadget" << endl;
    cout << "-i N                    open device N " << endl;
    cout << "     -s                 reset arto usb device N" << endl;
    cout << "     -r                 ROMCODE stage cmd" << endl;
    cout << "        -f xxxx         goto UPGRADE mode from ROMCODE mode using spl path XXXX" << endl;
    cout << "        -f xxxx -bb_cfg yyyy" << endl;
    cout << "                        goto UPGRADE mode from ROMCODE mode using spl path XXXX and update bb cfg using path YYYY" << endl;
    cout << "        -upload count_of_file loadaddr_0 filepath_0 loadaddr_1 filepath_1 ..." << endl;
    cout << "                        device N will UPLOAD all files to address" << endl;
    cout << "        -write addr val device N will write addr with val" << endl;
    cout << "     -u                 UBOOT stage cmd" << endl;
    cout << "        -f xxxx         upgrade device in UBOOT using image path XXXX" << endl;
    cout << "        -upload count_of_file loadaddr_0 filepath_0 loadaddr_1 filepath_1 ..." << endl;
    cout << "                        device N will UPLOAD all files to address" << endl;
    cout << "        -download count_of_file addr_0 len_0 filepath_0 addr_1 len_1 filepath_1 ..." << endl;
    cout << "                        device N will DOWNLOAD all address data to files" << endl;
    cout << "        -write addr val device N will write addr with val" << endl;
    cout << "        -read addr      device N will read addr and return val" << endl;
    return 0;
}

int ar8030_usb_tool::usb_tool_command_parse(int argc, char* argv[])
{
    int             index;
    int             i;

    if (1 == argc)
    {
        usb_tool_command_help();
        return 0;
    }

    if (search_param(argc, argv, "-l") >= 0)
    {
        usb->usb_print_dev_list();
    }
    else
    {
        //ar8030_upgrade(0, string(argv[get_param(argc, argv, "-f")]));
        i = get_param(argc, argv, "-i");
        if (i < 0 || NULL == argv[i])
        {
            cout << "must input device num" << endl;
            return -1;
        }

        i = atoi(argv[i]);
        handle = usb->usb_open_by_index(i);
        if (NULL == handle)
        {
            cout << "open device <" << i << "> failed!" << endl;
            return -1;
        }

        if (search_param(argc, argv, "-r") >= 0)
        {
            index = 0;

            if ((index = get_param(argc, argv, "-upload")) >= 0 && NULL != argv[index])
            {
                int count = atoi(argv[index]);
                int j = 0;
                int ret = 0;

                for (j = 0; j < count; ++j)
                {
                    cout << j << ":upload file " << string(argv[index + j * 2 + 2]) << " to addr: 0x" << hex << strtol(argv[index + j * 2 + 1], NULL, 16) << dec << endl;
                    ret = usb_tool_upload_file_romcode(strtol(argv[index + j * 2 + 1], NULL, 16), string(argv[index + j * 2 + 2]));
                }

                if (ret < 0)
                    return -1;
            }

            if ((index = get_param(argc, argv, "-write")) >= 0 && NULL != argv[index] && NULL != argv[index + 1])
            {
                int ret = 0;
                cout << "write 0x" << hex << strtol(argv[index], NULL, 16) <<
                    ": 0x" << strtol(argv[index + 1], NULL, 16) << dec << endl;
                ret = write_reg32(strtol(argv[index], NULL, 16), strtol(argv[index + 1], NULL, 16));
                if (ret < 0)
                    return -1;
            }

            if (get_param(argc, argv, "-f") >= 0)
            {
                if (get_param(argc, argv, "-bb_cfg") >= 0)
                    usb_tool_romcode_2_upgrade(string(argv[get_param(argc, argv, "-f")]), string(argv[get_param(argc, argv, "-bb_cfg")]));
                else
                    usb_tool_romcode_2_upgrade(string(argv[get_param(argc, argv, "-f")]), "");
            }
            else
            {
                //cout << "must input spl file path" << endl;
            }
        }
        else if (search_param(argc, argv, "-u") >= 0)
        {
            index = 0;

            if (usb->usb_class_configure(handle, i) < 0)
            {
                cout << "config class device <" << i << "> failed!" << endl;
                return -1;
            }

            if (search_param(argc, argv, "-send") >= 0)
            {
                send_speed_test();
            }

            if (search_param(argc, argv, "-recv") >= 0)
            {
                recv_speed_test();
            }

            if (search_param(argc, argv, "-echo") >= 0)
            {
                echo_speed_test();
            }

            if (search_param(argc, argv, "-f") >= 0)
            {
                ar8030_upgrade(i, string(argv[get_param(argc, argv, "-f")]));
            }

            /*if ((index = get_param(argc, argv, "-upload")) >= 0)
            {
                int count = atoi(argv[index]);
                int j = 0;
                int ret = 0;

                for (j = 0; j < count; ++j)
                {
                    cout << j << ":upload file " << string(argv[index + j * 2 + 2]) << " to addr: 0x" << hex << strtol(argv[index + j * 2 + 1], NULL, 16) << dec << endl;
                    ret = usb_tool_upload_file_uboot(i, strtol(argv[index + j * 2 + 1], NULL, 16), string(argv[index + j * 2 + 2]));
                }

                if (ret < 0)
                    return -1;
            }

            if ((index = get_param(argc, argv, "-download")) >= 0)
            {
                int count = atoi(argv[index]);
                int j = 0;
                int ret = 0;

                for (j = 0; j < count; ++j)
                {
                    cout << j << ":download " << atoi(argv[index + j * 3 + 2]) <<
                        "Bytes from addr: 0x" << hex << strtol(argv[index + j * 3 + 1], NULL, 16) << dec <<
                        " to file: " << string(argv[index + j * 3 + 3]) << endl;
                    ret = usb_tool_download_file_uboot(i, strtol(argv[index + j * 3 + 1], NULL, 16),
                        atoi(argv[index + j * 3 + 2]), string(argv[index + j * 3 + 3]));
                }

                if (ret < 0)
                    return -1;
            }

            if ((index = get_param(argc, argv, "-write")) >= 0)
            {
                int ret = 0;
                cout << "write 0x" << hex << strtol(argv[index], NULL, 16) <<
                    ": 0x" << strtol(argv[index + 1], NULL, 16) << dec << endl;
                ret = write_reg32_rtos(i, strtol(argv[index], NULL, 16), strtol(argv[index + 1], NULL, 16));
                if (ret < 0)
                    return -1;
            }

            if ((index = get_param(argc, argv, "-read")) >= 0)
            {
                int ret = 0;
                unsigned int val;
                ret = read_reg32_rtos(i, strtol(argv[index], NULL, 16), &val);
                if (ret < 0)
                    return -1;
                else
                    cout << "0x" << hex << strtol(argv[index], NULL, 16) << dec <<
                    ": 0x" << hex << val << dec << endl;
            }

            if (get_param(argc, argv, "-f") >= 0)
            {
                //usb_tool_upgrade_uboot(i, string(argv[get_param(argc, argv, "-f")]));
            }
            else
            {
                //cout << "must input spl file path" << endl;
            }*/
        }
        else if (search_param(argc, argv, "-n") >= 0)
        {

        }

        if (NULL != handle)
            usb->usb_close_dev(handle);
    }

    return 0;
}


int ar8030_usb_tool::write_reg32(unsigned int addr, unsigned int val)
{
    if (NULL == handle)
        return -1;

    if (usb->usb_transfer_data_with_addr_romcode(handle, addr, (unsigned char*)&val, sizeof(val), USB_TIMEOUT) < 0)
    {
        cout << "data transfer_data failed!" << endl;
        return -1;
    }

    return 0;
}

int ar8030_usb_tool::usb_tool_upload_file_romcode(unsigned long long addr, std::string file_path)
{
    fstream         file_data;
    unsigned int    file_len;
    char* data;

    if (NULL == handle)
        return -1;

    file_data.open(file_path, ios::in | ios::binary);
    if (!file_data.is_open())
    {
        cout << "file :" << file_path << " open failed!" << endl;
        return -1;
    }

    file_data.seekg(0, ios::end);
    file_len = file_data.tellg();
    file_data.seekg(0, ios::beg);

    try
    {
        data = new char[file_len];
        if (NULL == data)
        {
            cout << "new data failed!" << endl;
            return -1;
        }
    }
    catch (const bad_alloc& e)
    {
        cerr << "bad_alloc caught: " << e.what() << '\n';
        return -1;
    }

    file_data.read(data, file_len);
    file_data.close();

    if (usb->usb_transfer_data_with_addr_romcode(handle, addr, (unsigned char*)data, file_len, USB_TIMEOUT) < 0)
    {
        cout << "data transfer_data failed!" << endl;
        return -1;
    }

    delete[]data;

    return 0;
}

int ar8030_usb_tool::usb_tool_romcode_2_upgrade(std::string file_path, std::string bb_cfg_path)
{
    fstream         file_data;
    unsigned int    file_len;
    STRU_SPL_HEADER* spl_header = NULL;
    char* data;
    int             ret = 0, offset = 0;

    if (NULL == handle)
    {
        cout << "open usb device failed!" << endl;
        return -1;
    }

    file_data.open(file_path, ios::in | ios::binary);
    if (!file_data.is_open())
    {
        cout << "file :" << file_path << " open failed!" << endl;
        return -1;
    }

    file_data.seekg(0, ios::end);
    file_len = file_data.tellg();
    file_data.seekg(0, ios::beg);

    try
    {
        data = new char[file_len];
        if (NULL == data)
        {
            cout << "new data failed!" << endl;
            return -1;
        }
    }
    catch (const bad_alloc& e)
    {
        cerr << "bad_alloc caught: " << e.what() << '\n';
        return -1;
    }

    file_data.read(data, file_len);

    //parsing upgrade file header,to get load address for each partion 
    spl_header = (STRU_SPL_HEADER*)data;

    //spl header
    if (usb->usb_transfer_data_with_addr_romcode(handle, SPL_HEADER_LOAD_ADDR, (unsigned char*)data, spl_header->header_len, USB_TIMEOUT) < 0)
    {
        cout << "data transfer_data failed!" << endl;
        delete[]data;
        file_data.close();
        return -1;
    }

    offset += ROUNDUP(spl_header->header_len, SPL_IMAGE_SIZE_ALIGN);

    if (spl_header->troot_len)
    {
        if ((ret = usb->usb_transfer_data_with_addr_romcode(handle, spl_header->troot_load_addr,
            (unsigned char*)(data + offset), spl_header->troot_len, USB_TIMEOUT)) < 0)
        {
            cout << "upgrade transfer failed!(addr: 0x" << spl_header->troot_load_addr << ")" << endl;
        }

        offset += ROUNDUP(spl_header->troot_len, SPL_IMAGE_SIZE_ALIGN);

        if ((ret = usb->usb_transfer_data_with_addr_romcode(handle, spl_header->signature_load_addr,
            (unsigned char*)(data + offset), spl_header->signature_len, USB_TIMEOUT)) < 0)
        {
            cout << "upgrade transfer failed!(addr: 0x" << spl_header->troot_load_addr << ")" << endl;
        }

        offset += ROUNDUP(spl_header->signature_len, SPL_IMAGE_SIZE_ALIGN);
    }

    //send spl
    if ((ret = usb->usb_transfer_data_with_addr_romcode(handle, spl_header->spl_load_addr,
        (unsigned char*)(data + offset), spl_header->spl_len, USB_TIMEOUT)) < 0)
    {
        cout << "upgrade transfer failed!(addr: 0x" << spl_header->spl_load_addr << ")" << endl;
    }

    //send new bb cfg
    if (!bb_cfg_path.empty())
    {
        char* data_bb;

        file_data.close();

        file_data.open(bb_cfg_path, ios::in | ios::binary);
        if (!file_data.is_open())
        {
            cout << "file :" << bb_cfg_path << " open failed!" << endl;
            return -1;
        }

        file_data.seekg(0, ios::end);
        file_len = file_data.tellg();
        file_data.seekg(0, ios::beg);

        try
        {
            data_bb = new char[file_len];
            if (NULL == data_bb)
            {
                cout << "new data failed!" << endl;
                return -1;
            }
        }
        catch (const bad_alloc& e)
        {
            cerr << "bad_alloc caught: " << e.what() << '\n';
            return -1;
        }

        file_data.read(data_bb, file_len);

        if ((ret = usb->usb_transfer_data_with_addr_romcode(handle, spl_header->signature_load_addr,
            (unsigned char*)data_bb, file_len, USB_TIMEOUT)) < 0)
        {
            cout << "updata bb_cfg failed!(addr: 0x" << spl_header->troot_load_addr << ")" << endl;
        }
        cout << "updata bb_cfg success!" << endl;
        delete[]data_bb;
    }

    //end usb boot, ar9301 will goto bl2
    if ((ret = usb->usb_exit_romcode(handle, USB_TIMEOUT)) < 0)
    {
        cout << "usb_exit_romcode failed!" << endl;
        delete[]data;
        file_data.close();
        return -1;
    }

    cout << "exit_usb_boot_in_bl1 success!" << endl;

    delete[]data;
    file_data.close();

    return 0;
}
